/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.netbeans.modules.gradle.newproject;

import java.io.File;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFileChooser;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import static org.netbeans.modules.gradle.newproject.ProjectAttributesPanelVisual.PROP_PROJECT_NAME;
import static org.netbeans.modules.gradle.spi.newproject.BaseGradleWizardIterator.PROP_NAME;
import static org.netbeans.modules.gradle.spi.newproject.BaseGradleWizardIterator.PROP_PACKAGE_BASE;
import static org.netbeans.modules.gradle.spi.newproject.GradleInitWizard.*;
import org.netbeans.spi.project.ui.support.CommonProjectActions;
import org.netbeans.spi.project.ui.support.ProjectChooser;
import org.openide.WizardDescriptor;
import org.openide.filesystems.FileUtil;

/**
 *
 * @author lkishalmi
 */
public class GradleInitPanelVisual extends javax.swing.JPanel {

    /**
     * Creates new form GradleInitPanelVisual
     */
    public GradleInitPanelVisual() {
        initComponents();

        cbDSL.setModel(new DefaultComboBoxModel<>(GradleDSL.values()));
        tfProjectName.getDocument().addDocumentListener(fieldUpdater);
        tfLocation.getDocument().addDocumentListener(fieldUpdater);
        tfPackageName.getDocument().addDocumentListener(fieldUpdater);


    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        lbProjectName = new javax.swing.JLabel();
        tfProjectName = new javax.swing.JTextField();
        lbLocation = new javax.swing.JLabel();
        tfLocation = new javax.swing.JTextField();
        btBrowse = new javax.swing.JButton();
        lbProjectFolder = new javax.swing.JLabel();
        tfProjectFolder = new javax.swing.JTextField();
        lbPackageName = new javax.swing.JLabel();
        tfPackageName = new javax.swing.JTextField();
        lbJavaVersion = new javax.swing.JLabel();
        cbJavaVersion = new javax.swing.JComboBox<>();
        lbTestFramework = new javax.swing.JLabel();
        cbTestFramework = new javax.swing.JComboBox<>();
        lbDSL = new javax.swing.JLabel();
        cbDSL = new javax.swing.JComboBox<>();
        cbComments = new javax.swing.JCheckBox();

        lbProjectName.setLabelFor(tfProjectName);
        org.openide.awt.Mnemonics.setLocalizedText(lbProjectName, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.lbProjectName.text")); // NOI18N

        lbLocation.setLabelFor(tfLocation);
        org.openide.awt.Mnemonics.setLocalizedText(lbLocation, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.lbLocation.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(btBrowse, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.btBrowse.text")); // NOI18N
        btBrowse.setActionCommand(org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.btBrowse.actionCommand")); // NOI18N
        btBrowse.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btBrowseActionPerformed(evt);
            }
        });

        lbProjectFolder.setLabelFor(tfProjectFolder);
        org.openide.awt.Mnemonics.setLocalizedText(lbProjectFolder, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.lbProjectFolder.text")); // NOI18N

        tfProjectFolder.setEditable(false);

        lbPackageName.setLabelFor(tfPackageName);
        org.openide.awt.Mnemonics.setLocalizedText(lbPackageName, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.lbPackageName.text")); // NOI18N

        lbJavaVersion.setLabelFor(cbJavaVersion);
        org.openide.awt.Mnemonics.setLocalizedText(lbJavaVersion, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.lbJavaVersion.text")); // NOI18N

        lbTestFramework.setLabelFor(cbTestFramework);
        org.openide.awt.Mnemonics.setLocalizedText(lbTestFramework, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.lbTestFramework.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(lbDSL, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.lbDSL.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(cbComments, org.openide.util.NbBundle.getMessage(GradleInitPanelVisual.class, "GradleInitPanelVisual.cbComments.text")); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(lbPackageName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(lbJavaVersion, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(lbLocation, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(lbProjectFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(lbProjectName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addComponent(lbTestFramework, javax.swing.GroupLayout.DEFAULT_SIZE, 141, Short.MAX_VALUE)
                    .addComponent(lbDSL, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(cbDSL, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGap(18, 18, 18)
                        .addComponent(cbComments))
                    .addComponent(cbJavaVersion, javax.swing.GroupLayout.Alignment.LEADING, 0, 291, Short.MAX_VALUE)
                    .addComponent(tfLocation, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(tfProjectName, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(tfProjectFolder, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(tfPackageName, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(cbTestFramework, javax.swing.GroupLayout.Alignment.LEADING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btBrowse)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lbProjectName)
                    .addComponent(tfProjectName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lbLocation)
                    .addComponent(tfLocation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btBrowse))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(lbProjectFolder)
                    .addComponent(tfProjectFolder, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(tfPackageName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lbPackageName))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cbJavaVersion, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lbJavaVersion))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cbTestFramework, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lbTestFramework))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cbComments)
                    .addComponent(lbDSL)
                    .addComponent(cbDSL, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(54, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void btBrowseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btBrowseActionPerformed
        if ("BROWSE".equals(evt.getActionCommand())) { //NOI18N
            JFileChooser chooser = new JFileChooser();
            chooser.setCurrentDirectory(null);
            chooser.setDialogTitle(Bundle.TIT_Select_Project_Location());
            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            String path = tfLocation.getText();
            if (path.length() > 0) {
                File f = new File(path);
                if (f.exists()) {
                    chooser.setSelectedFile(f);
                }
            }
            if (JFileChooser.APPROVE_OPTION == chooser.showOpenDialog(this)) {
                File projectDir = chooser.getSelectedFile();
                tfLocation.setText(FileUtil.normalizeFile(projectDir).getAbsolutePath());
            }

        }
    }//GEN-LAST:event_btBrowseActionPerformed

    void read(WizardDescriptor settings) {
        NewProjectSettings newproject = NewProjectSettings.getDefault();
        File loc = (File) settings.getProperty(CommonProjectActions.PROJECT_PARENT_FOLDER);
        if (loc == null || loc.getParentFile() == null || !loc.getParentFile().isDirectory()) {
            loc = ProjectChooser.getProjectsFolder();
        }
        tfLocation.setText(loc.getAbsolutePath());

        String name = (String) settings.getProperty(PROP_NAME);

        name = name != null ? name : firstAvailableName(loc, "gradleproject"); //NOI18N
        tfProjectName.setText(name);

        String packageBase = (String) settings.getProperty(PROP_PACKAGE_BASE);

        if (packageBase != null) {
            tfPackageName.setText(packageBase);
        } else {
            String packagePrefix = newproject.getPackagePrefix();
            tfPackageName.setText(packagePrefix + name);
        }
        adjustPackageBase();

        if (settings.getProperty(PROP_JAVA_VERSIONS) != null) {
            List<Integer> javaVersions = (List<Integer>) settings.getProperty(PROP_JAVA_VERSIONS);
            DefaultComboBoxModel<Integer> versionModel = new DefaultComboBoxModel<>(javaVersions.toArray(Integer[]::new));
            cbJavaVersion.setModel(versionModel);

            if (settings.getProperty(PROP_JAVA_VERSION) != null) {
                cbJavaVersion.setSelectedItem(settings.getProperty(PROP_JAVA_VERSION));
            }
        } else {
            lbJavaVersion.setVisible(false);
            cbJavaVersion.setVisible(false);
        }

        if (settings.getProperty(PROP_TEST_FRAMEWORKS) != null) {
            List<TestFramework> testframeworks = (List<TestFramework>) settings.getProperty(PROP_TEST_FRAMEWORKS);
            DefaultComboBoxModel<TestFramework> frameworkModel = new DefaultComboBoxModel<>(testframeworks.toArray(TestFramework[]::new));
            cbTestFramework.setModel(frameworkModel);
            if (settings.getProperty(PROP_TEST_FRAMEWORK) != null) {
                cbTestFramework.setSelectedItem(settings.getProperty(PROP_TEST_FRAMEWORK));
            }
        } else {
            lbTestFramework.setVisible(false);
            cbTestFramework.setVisible(false);
        }

        GradleDSL dsl = (GradleDSL) settings.getProperty(PROP_DSL);
        cbDSL.setSelectedItem(dsl != null ? dsl : newproject.getGradleDSL());

        Boolean comments = (Boolean) settings.getProperty(PROP_COMMENTS);
        cbComments.setSelected(comments != null ? comments : newproject.getGenerateComments());

        tfProjectName.selectAll();

    }

    void write(WizardDescriptor settings) {
        NewProjectSettings newproject = NewProjectSettings.getDefault();
        File projectFolder = new File(tfLocation.getText());
        ProjectChooser.setProjectsFolder(projectFolder);
        settings.putProperty(CommonProjectActions.PROJECT_PARENT_FOLDER,
                projectFolder);
        settings.putProperty(PROP_NAME, tfProjectName.getText());
        if (tfPackageName.isVisible()) {
            String pkg = tfPackageName.getText();
            settings.putProperty(PROP_PACKAGE_BASE, pkg);
            String derivedPackage = derivedPackage();
            if (pkg.endsWith(derivedPackage)) {
                String prefix = pkg.substring(0, pkg.length() - derivedPackage.length());
                newproject.setPackagePrefix(prefix);
            }
        }

        if (settings.getProperty(PROP_JAVA_VERSIONS) != null) {
            settings.putProperty(PROP_JAVA_VERSION, cbJavaVersion.getSelectedItem());
        }

        if (settings.getProperty(PROP_TEST_FRAMEWORKS) != null) {
            settings.putProperty(PROP_TEST_FRAMEWORK, cbTestFramework.getSelectedItem());
        }

        settings.putProperty(PROP_DSL, cbDSL.getSelectedItem());
        newproject.setGradleDSL((GradleDSL) cbDSL.getSelectedItem());

        settings.putProperty(PROP_COMMENTS, cbComments.isSelected());
        newproject.setGenerateComments(cbComments.isSelected());
    }

    private static String firstAvailableName(File dir, String baseName) {
        int index = 1;
        String name;
        File folder;
        do {
            name = baseName + String.valueOf(index++);
            folder = new File(dir, name);
        } while (folder.exists());
        return name;
    }

    private void updateTextFields(DocumentEvent e) {
        Document doc = e.getDocument();

        if (tfProjectName.getDocument() == doc || tfLocation.getDocument() == doc) {
            File location = new File(tfLocation.getText());
            if (location.isDirectory()) {
                tfProjectFolder.setText(tfLocation.getText() + File.separator + tfProjectName.getText());
            } else {
                tfProjectFolder.setText(tfLocation.getText());
            }
        }

        if (!packageNameChanged && (tfProjectName.getDocument() == doc)) {
            tfPackageName.getDocument().removeDocumentListener(fieldUpdater);
            adjustPackageBase();
            tfPackageName.getDocument().addDocumentListener(fieldUpdater);
        }

        if (tfProjectName.getDocument() == doc) {
            firePropertyChange(PROP_PROJECT_NAME, null, tfProjectName.getText());
        }
    }

    private String derivedPackage() {
        return tfProjectName.getText()
                .replace('_', '.')
                .replace('-', '.');
    }
    private void  adjustPackageBase() {
        String derivedPackage = derivedPackage();
        String pkg = tfPackageName.getText();
        if ((packageSuffix != null) && pkg.endsWith(packageSuffix)) {
            String newPkg = pkg.substring(0, pkg.length() - packageSuffix.length()) + derivedPackage;

            tfPackageName.setText(newPkg);
        }
        packageSuffix = derivedPackage;
    }

    // Change the package name upon the project name till it's not directly edited
    private boolean packageNameChanged = false;
    private String packageSuffix;
    private final DocumentListener fieldUpdater = new DocumentListener() {
        @Override
        public void insertUpdate(DocumentEvent e) {
            updateTextFields(e);
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            updateTextFields(e);
        }

        @Override
        public void changedUpdate(DocumentEvent e) {
            updateTextFields(e);
        }
    };

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btBrowse;
    private javax.swing.JCheckBox cbComments;
    private javax.swing.JComboBox<GradleDSL> cbDSL;
    private javax.swing.JComboBox<Integer> cbJavaVersion;
    private javax.swing.JComboBox<TestFramework> cbTestFramework;
    private javax.swing.JLabel lbDSL;
    private javax.swing.JLabel lbJavaVersion;
    private javax.swing.JLabel lbLocation;
    private javax.swing.JLabel lbPackageName;
    private javax.swing.JLabel lbProjectFolder;
    private javax.swing.JLabel lbProjectName;
    private javax.swing.JLabel lbTestFramework;
    private javax.swing.JTextField tfLocation;
    private javax.swing.JTextField tfPackageName;
    private javax.swing.JTextField tfProjectFolder;
    private javax.swing.JTextField tfProjectName;
    // End of variables declaration//GEN-END:variables
}
